package com.kinoshita.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kinoshita.admin.entity.SysAdmin;
import com.kinoshita.admin.entity.SysAdminRole;
import com.kinoshita.admin.mapper.SysAdminMapper;
import com.kinoshita.admin.mapper.SysAdminRoleMapper;
import com.kinoshita.admin.service.IAdminService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kinoshita.admin.api.domain.AdminDO;
import com.kinoshita.admin.api.query.AdminQueryDO;
import com.kinoshita.common.bean.BeanUtilsExtends;
import com.kinoshita.common.exception.SystemException;
import com.kinoshita.common.logger.LoggerUtil;
import com.kinoshita.common.result.PageDO;
import com.kinoshita.common.result.ResultDO;
import com.kinoshita.common.status.Constant;
import com.kinoshita.common.status.OpCode;
import com.kinoshita.common.status.StatusCode;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author reagan
 * @since 2022-08-29
 */
@Service
public class AdminServiceImpl extends ServiceImpl<SysAdminMapper, SysAdmin> implements IAdminService {

    private static Logger logger = LoggerFactory.getLogger(AdminServiceImpl.class);

    @Autowired
    private SysAdminRoleMapper sysAdminRoleMapper;

    @Autowired
    private SysAdminMapper sysAdminMapper;

    @Autowired
    private LoggerUtil loggerUtil;

    @Override
    public ResultDO add(AdminDO domain) {
        SysAdmin entity = new SysAdmin();
        ResultDO resultDO = BeanUtilsExtends.copy(entity, domain);
        boolean res = false;
        if(!resultDO.isSuccess()) {
            throw new SystemException(resultDO.getStatusCode());
        }
        entity.setCreateDate(LocalDateTime.now());
        entity.setModifiDate(entity.getModifiDate());
        entity.setIsDelete(Constant.IS_NOT_DELETE);
        entity.setStatus(Constant.OK);
        entity.setCreator(domain.getCreator());
        entity.setModifier(entity.getCreator());
        entity.setPassword(DigestUtils.md5DigestAsHex(domain.getPassword().getBytes()));
        res = this.save(entity);
        loggerUtil.setInfo(this.getClass().getName() + " add", OpCode.OP_CREATE, domain.getCreator(), "");
        logger.info(loggerUtil.toString());
        if(!res) {
            throw new SystemException(StatusCode.USER_ADD_ERROR);
        }
        bindRole(entity.getId(), domain.getRoleIds());
        return resultDO;
    }

    public void bindRole(Long adminId, List<Long> roleIds) {
        roleIds.stream().forEach(roleId->{
            SysAdminRole entity = new SysAdminRole();
            entity.setUserId(adminId);
            entity.setRoleId(roleId);
            int row = sysAdminRoleMapper.insert(entity);
            if(row < 0) {
                throw new SystemException(StatusCode.ROLE_BIND_USER_ERROR);
            }
        });
        loggerUtil.setInfo(this.getClass().getName() + " bindRole", OpCode.OP_CREATE, "", "");
        logger.info(loggerUtil.toString());
    }

    public void unBindRole(Long adminId) {
        int row = sysAdminRoleMapper.delete(Wrappers.<SysAdminRole>lambdaQuery().eq(SysAdminRole::getUserId, adminId));
        if(row < 0) {
            throw new SystemException(StatusCode.ROLE_UNBIND_USER_ERROR);
        }
        loggerUtil.setInfo(this.getClass().getName() + " unBindRole", OpCode.OP_DELETE, "", "");
        logger.info(loggerUtil.toString());
    }

    @Override
    public ResultDO edit(AdminDO domain) {
        SysAdmin entity = new SysAdmin();
        ResultDO resultDO = BeanUtilsExtends.copy(entity, domain);
        boolean res = false;
        if(!resultDO.isSuccess()) {
            throw new SystemException(resultDO.getStatusCode());
        }
        entity.setModifiDate(LocalDateTime.now());
        entity.setModifier("");
        res = this.updateById(entity);
        loggerUtil.setInfo(this.getClass().getName() + " edit", OpCode.OP_EDIT, domain.getCreator(), "");
        logger.info(loggerUtil.toString());
        if(!res) {
            throw new SystemException(StatusCode.USER_EDIT_ERROR);
        }
        if(domain.getRoleIds().size() != 0) {
            unBindRole(domain.getId());
            bindRole(domain.getId(), domain.getRoleIds());
        }
        return resultDO;
    }

    @Override
    public ResultDO delete(Long id) {
        ResultDO resultDO = new ResultDO();
        SysAdmin entity = new SysAdmin();
        entity.setId(id);
        entity.setIsDelete(Constant.IS_DELETE);
        entity.setModifiDate(LocalDateTime.now());
        entity.setModifier("");
        boolean res = this.updateById(entity);
        loggerUtil.setInfo(this.getClass().getName() + " delete", OpCode.OP_EDIT, "", "");
        logger.info(loggerUtil.toString());
        if(!res) {
            throw new SystemException(StatusCode.USER_EDIT_ERROR);
        }
        unBindRole(id);
        return resultDO;
    }

    @Override
    public ResultDO get(Long id) {
        ResultDO resultDO = new ResultDO();
        SysAdmin entity = this.getById(id);
        AdminDO domain = getDomain(entity);
        loggerUtil.setInfo(this.getClass().getName() + " get", OpCode.OP_GET, "", "");
        logger.info(loggerUtil.toString());
        if(ObjectUtils.isEmpty(domain)) {
            throw new SystemException(StatusCode.USER_GET_ERROR);
        }
        resultDO.setModel(Constant.DATA_MODEL_KEY, domain);
        return resultDO;
    }

    @Override
    public ResultDO query(AdminQueryDO query) {
        SysAdmin entity = new SysAdmin();
        ResultDO resultDO = BeanUtilsExtends.copy(entity,query);
        if (!resultDO.isSuccess()) {
            throw new SystemException(resultDO.getStatusCode());
        }
        QueryWrapper<SysAdmin> wrapper = new QueryWrapper<SysAdmin>(entity);
        Page<SysAdmin> page = new Page<>(query.getCurrentPage(),query.getPageSize());
        IPage<SysAdmin> iPage = null;
        iPage = sysAdminMapper.selectPage(page, wrapper);
        List<AdminDO> doList = getDomainCollection(iPage.getRecords());
        PageDO<AdminDO> pageDO = new PageDO<>();
        pageDO.setCurrentPage(iPage.getCurrent());
        pageDO.setPageCount(iPage.getPages());
        pageDO.setPageSize(iPage.getSize());
        pageDO.setRowCount(iPage.getTotal());
        pageDO.setData(doList);
        loggerUtil.setInfo(this.getClass().getName() + " query", OpCode.OP_QUERY, "", "");
        logger.info(loggerUtil.toString());
        resultDO.setModel(Constant.DATA_MODEL_KEY, pageDO);
        return resultDO;
    }

    @Override
    public ResultDO getAdminByName(String username) {
        ResultDO resultDO = new ResultDO();
        SysAdmin entity = baseMapper.selectOne(Wrappers.<SysAdmin>lambdaQuery()
                .eq(SysAdmin::getUsername, username)
                .eq(SysAdmin::getStatus, Constant.OK)
                .eq(SysAdmin::getIsDelete, Constant.IS_NOT_DELETE));
        if(ObjectUtils.isEmpty(entity)) {
            resultDO.setSuccess(false);
            return resultDO;
        }
        loggerUtil.setInfo(this.getClass().getName() + " getAdminByName", OpCode.OP_AMIND_LOGIN, username, "");
        logger.info(loggerUtil.toString());
        AdminDO domain = getDomain(entity);
        resultDO.setModel(Constant.DATA_MODEL_KEY, domain);
        return resultDO;
    }

    private AdminDO getDomain(SysAdmin entity) {
        AdminDO domain = new AdminDO();
        if(ObjectUtils.isEmpty(entity)) {
            return null;
        }
        domain = BeanUtilsExtends.copyProperties(domain, entity) ? domain : null;
        return domain;
    }

    private List<AdminDO> getDomainCollection(List<SysAdmin> list) {
        List<AdminDO> doList = new ArrayList<>();
        if(list.size() > 0) {
            for(SysAdmin entity : list) {
                AdminDO domain = this.getDomain(entity);
                if(domain == null) {
                    return Collections.emptyList();
                }
                doList.add(domain);
            }
        } else {
            return Collections.emptyList();
        }
        return doList;
    }

}
